package com.runewbie.linkedlist.singlelinkedlist;

/**
 * @description: 使用带head头的单向链表实现 –水浒英雄排行榜管理 
 * 				 1、完成对英雄人物的增删改查操作， 注: 删除和修改,查找
 *               2、第一种方法在添加英雄时，直接添加到链表的尾部
 *               3、第二种方式在添加英雄时，根据排名将英雄插入到指定位置(如果有这个排名，则添加失败，并给出提示)
 * @author: runewbie
 * @date: 2020年6月7日 下午12:01:05
 * @version V4.0（实现单链表节点的删除）
 *
 */
public class SingleLinkedListDemo4 {

	// 测试
	public static void main(String[] args) {
		// 创建节点
		HeroNode4 hero1 = new HeroNode4(1, "宋江", "呼保义");
		HeroNode4 hero2 = new HeroNode4(2, "卢俊义", "玉麒麟");
		HeroNode4 hero3 = new HeroNode4(3, "吴用", "智多星");
		HeroNode4 hero4 = new HeroNode4(4, "公孙胜", "入云龙");

		// 创建链表
		SingleLinkedList4 singleLinkedList4 = new SingleLinkedList4();

		// 添加节点
//		singleLinkedList4.add(hero1);
//		singleLinkedList4.add(hero4);
//		singleLinkedList4.add(hero2);
//		singleLinkedList4.add(hero3);
		
		// 测试按照编号顺序添加节点
		singleLinkedList4.addByOrder(hero1);
		singleLinkedList4.addByOrder(hero4);
		singleLinkedList4.addByOrder(hero2);
		singleLinkedList4.addByOrder(hero3);
		singleLinkedList4.addByOrder(hero3);

		// 遍历显示
		singleLinkedList4.list();
		
		//修改节点
		HeroNode4 newHeroNode3 = new HeroNode4(2, "小卢", "河北玉麒麟");
		singleLinkedList4.update(newHeroNode3);
		
		// 遍历显示
		System.out.println("修改后的链表");
		singleLinkedList4.list();
		
		//删除一个节点
		singleLinkedList4.del(1);
		singleLinkedList4.del(2);
		singleLinkedList4.del(4);
		singleLinkedList4.del(0);
		System.out.println("删除后的链表情况：");
		singleLinkedList4.list();
		
	}

}

// 定义SingleLinkedList管理水浒英雄
class SingleLinkedList4 {
	// 先初始化一个头结点，头结点不动，不存放具体的数据
	private HeroNode4 head = new HeroNode4(0, null, null);

	// 添加节点到单向链表
	// 思路：当不考虑编号的顺序时
	// 1、找到当前链表的最后节点
	// 2、将最后这个节点的next指向新的节点
	public void add(HeroNode4 HeroNode4) {
		// 因为head节点不能动，因此我们需要一个辅助遍历 temp
		HeroNode4 temp = head;
		// 遍历链表，找到最后
		while (true) {
			// 找到链表的最后
			if (temp.next == null) {
				break;
			}
			// 如果没有找到最后，将temp后移
			temp = temp.next;
		}
		// 当退出while循环时，temp指向了链表的最后
		// 将最后这个节点的next指向新的节点
		temp.next = HeroNode4;
	}

	// 第二种方式在添加英雄的时候，根据排名将英雄插入到指定位置
	// (如果有这个排名，则添加失败，并给出提示)
	public void addByOrder(HeroNode4 HeroNode4) {
		// 因为头节点不能动，所以仍然通过一个辅助指针（变量）来帮助找到添加的位置
		// 因为是单链表，因此找的temp是位于添加位置的前一个节点，否则插入不了
		HeroNode4 temp = head;
		boolean flag = false;// flag标识添加的编号是否存在，默认为false
		
		while (true) {
			if (temp.next == null) {// 说明temp已经在链表的最后
				break;
			}
			if (temp.next.no > HeroNode4.no) {// 位置找到，就在temp的后面插入
				break;
			} else if (temp.next.no == HeroNode4.no) {// 说明希望添加的heerNode的编号已经存在
				flag = true;// 说明编号已经存在
				break;
			}
			
			temp = temp.next;// 后移，遍历当前链表
		}
		
		// 判断flag的值
		if (flag) {
			System.out.printf("准备插入的英雄的编号 %d 已经存在了，不能加入\n", HeroNode4.no);
		} else {
			// 插入到链表中，放在temp的后面
			HeroNode4.next = temp.next;
			temp.next = HeroNode4;
		}
	}
	
	// 修改节点信息，根据no编号来修改，即no编号不能改
	// 说明：
	// 根据heroNode3 的 no 来修改即可
	public void update(HeroNode4 HeroNode4) {
		// 判断是否为空
		if (head.next == null) {
			System.out.println("链表为空~~");
			return;
		}
		// 找到需要修改的节点，根据no编号
		// 定义一个辅助变量
		HeroNode4 temp = head.next;
		boolean flag = false;// 表示是否找到该节点
		while (true) {
			if (temp == null) {
				break;// 链表已经遍历完
			}
			if (temp.no == HeroNode4.no) {
				// 找到了
				flag = true;
				break;
			}
			// 指针先向后移动
			temp = temp.next;
		}
		// 根据flag判断是否找到要修改的节点
		if (flag) {
			temp.name = HeroNode4.name;
			temp.nickName = HeroNode4.nickName;
		} else {
			System.out.printf("没有找到编号为%d的节点，不能修改\n", HeroNode4.no);
		}
	}
	
	//删除节点
	//思路：
	//1、head不能动，因此我们需要一个temp辅助节点找到待删除节点的前一个节点
	//2、说明在比较时，是temp.next.no 和需要删除的节点的no比较
	public void del(int no) {
		HeroNode4 temp = head;
		boolean flag = false;// 标志是否找到待删除的节点
		while (true) {
			if (temp.next == null) {// 已经到链表的最后
				break;
			}
			if (temp.next.no == no) {
				// 找到待删除节点的点一个节点temp
				flag = true;
				break;
			}
			temp = temp.next;// temp后移到下一个节点
		}
		// 判断flag
		if (flag) {// 如果找到了
			// 可以删除该节点
			temp.next = temp.next.next;
		} else {
			System.out.printf("要删除的节点 %d 不存在\n", no);
		}
	}

	// 显示链表[遍历]
	public void list() {
		// 判断链表是否为空
		if (head.next == null) {
			System.out.println("链表为空");
			return;
		}
		// 因为头节点不能动，因此需要一个辅助变量来进行遍历
		HeroNode4 temp = head.next;
		while (true) {
			// 判断是否到了链表最后
			if (temp == null) {
				break;
			}
			// 输出节点的信息
			System.out.println(temp);
			// * 将temp后移，一定要小心，这里要是不后移的话，会导致死循环
			temp = temp.next;
		}
	}

}

//定义HeroNode，每个 HeroNode对象就是一个节点
class HeroNode4 {
	public int no;
	public String name;
	public String nickName;
	public HeroNode4 next;// 指向下一个节点
	// 构造器

	public HeroNode4(int no, String name, String nickName) {
		this.no = no;
		this.name = name;
		this.nickName = nickName;
	}

	// 为了显示方便，我们重写toString
	@Override
	public String toString() {
		return "HeroNode4 [no=" + no + ", name=" + name + ", nickName=" + nickName + "]";
	}
}